﻿//======================================================================
// Copyright (c) 苏州同程旅游网络科技有限公司. All rights reserved.
// 所属项目：Common
// 创 建 人：郭瑞山
// 创建日期：2/22/2012 10:49:06 AM
// 用    途：异常警报类。实现当系统出现异常，需要立即通知时，发送邮件给系统管理员的功能。
//====================================================================== 

namespace Common
{
    using System;
    using System.Data;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Text;

    /// <summary>
    /// 异常警报类。实现当系统出现异常，需要立即通知时，发送邮件给系统管理员的功能。
    /// </summary>
    [Serializable]
    public class ExceptionWarning
    {
        private string key = "_tcEmail_haha";
        private string mark = "";
        private Exception exception = null;
        private NameValueCollection extensionInfo = null;

        /// <summary>
        /// 出现的异常
        /// </summary>
        public virtual Exception Exception
        {
            get { return exception; }
            set { exception = value; }
        }

        /// <summary>
        /// 标记
        /// </summary>
        public virtual string Mark
        {
            get { return mark; }
            set { mark = value; }
        }

        /// <summary>
        /// 扩展信息
        /// </summary>
        public virtual NameValueCollection ExtensionInfo
        {
            get { return extensionInfo; }
            set { extensionInfo = value; }
        }

        /// <summary>
        /// 构造器
        /// </summary>
        public ExceptionWarning()
        {
            extensionInfo = new NameValueCollection();
        }

        /// <summary>
        /// 构造器
        /// </summary>
        /// <param name="ex">异常</param>
        public ExceptionWarning( Exception ex )
            : this()
        {
            this.exception = ex;
        }

        /// <summary>
        /// 构造器
        /// </summary>
        /// <param name="mark">标记</param>
        /// <param name="ex">异常</param>
        public ExceptionWarning( string mark, Exception ex )
            : this( ex )
        {
            this.mark = mark;
        }

        /// <summary>
        /// 发送异常警告信息
        /// </summary>
        /// <param name="to">收件人Email地址</param>
        /// <param name="chao">抄送人Email地址</param>
        public virtual void SendWarning( string to, string chao )
        {
            if ( string.IsNullOrEmpty( to ) )
                throw new ArgumentNullException( to );

            //if ( !Toolkit.IsValidEmail( to ) )
            //    throw new FormatException( "收件人[" + to + "]可能不是有效的电子邮件地址" );

            //if ( !string.IsNullOrEmpty( chao ) && !Toolkit.IsValidEmail( chao ) )
            //    throw new FormatException( "抄送人[" + chao + "]可能不是有效的电子邮件地址" );

            StringBuilder contentBuilder = new StringBuilder("错误详情如下所示：<br />");
            if ( this.Exception != null )
            {
                //Exception.Data
                if ( this.Exception.Data != null )
                {
                    HtmlTableBuilder data = new HtmlTableBuilder();
                    data.TrBegin().TdBegin( new HtmlProperty( new DictionaryEntry[] { new DictionaryEntry( "colspan", 2 ) } ), null, "Exception.Data" ).TdEnd().TrEnd();
                    foreach ( DictionaryEntry entry in this.Exception.Data )
                    {
                        data.TrBegin().TdBegin( entry.Key ).TdEnd().TdBegin( entry.Value ).TdEnd().TrEnd();
                    }
                    contentBuilder.Append( data );
                }
                //Exception.HelpLink
                if ( !string.IsNullOrEmpty( this.Exception.HelpLink ) )
                    contentBuilder.Append( new HtmlTableBuilder().TrBegin().TdBegin( "Exception.HelpLink" ).TdEnd().TdBegin( this.Exception.HelpLink ).TdEnd().TrEnd() );

                //Exception.Message
                contentBuilder.Append( new HtmlTableBuilder().TrBegin().TdBegin( "Exception.Message" ).TdEnd().TdBegin( this.Exception.Message ).TdEnd().TrEnd() );
                //Exception.Source
                contentBuilder.Append( new HtmlTableBuilder().TrBegin().TdBegin( "Exception.Source" ).TdEnd().TdBegin( this.Exception.Source ).TdEnd().TrEnd() );
                //Exception.StackTrace
                contentBuilder.Append( new HtmlTableBuilder().TrBegin().TdBegin( "Exception.StackTrace" ).TdEnd().TdBegin( System.Text.RegularExpressions.Regex.Replace( this.Exception.StackTrace, "([\u4e00-\u9fa5]+)", "<br />$1" ) ).TdEnd().TrEnd() );
                //Exception.TargetSite
                contentBuilder.Append( new HtmlTableBuilder().TrBegin().TdBegin( "Exception.TargetSite" ).TdEnd().TdBegin( this.Exception.TargetSite ).Append( "<br /> In " + this.Exception.TargetSite.ReflectedType.FullName ).TdEnd().TrEnd() );
                //Exception.InnerException
                if ( this.Exception.InnerException != null )
                    contentBuilder.Append( new HtmlTableBuilder().TrBegin().TdBegin( "Exception.InnerException" ).TdEnd().TdBegin( this.Exception.InnerException ).TdEnd().TrEnd() );
            }
            //ExtensionInfo
            if ( this.ExtensionInfo != null && this.ExtensionInfo.Count > 0 )
            {
                HtmlTableBuilder data = new HtmlTableBuilder();
                data.TrBegin().TdBegin( new HtmlProperty( new DictionaryEntry[] { new DictionaryEntry( "colspan", 2 ) } ), null, "ExtensionInfo" ).TdEnd().TrEnd();
                foreach ( string key in ExtensionInfo.Keys )
                {
                    data.TrBegin().TdBegin( key ).TdEnd().TdBegin( ExtensionInfo[key] ).TdEnd().TrEnd();
                }
                contentBuilder.Append( data );
            }

            string keyCode = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile( this.key + to, "md5" );
            if ( this.Exception != null )
                SendEmailHelper.SendEMail( to, chao, mark + " - " + this.Exception.Message, contentBuilder.ToString(), keyCode, true );
            else
                SendEmailHelper.SendEMail( to, chao, mark, contentBuilder.ToString(), keyCode, true );
        }
    }

    /// <summary>
    /// HTML Table 生成
    /// </summary>
    public class HtmlTableBuilder
    {
        private StringBuilder builder = null;

        public HtmlTableBuilder()
        {
            builder = new StringBuilder("<table border=\"1\">");
        }

        public HtmlTableBuilder( HtmlProperty proprety, HtmlStyle style )
        {
            builder = new StringBuilder( "<table" );
            if ( proprety != null )
                builder.Append( proprety.ToString() );
            if ( style != null )
                builder.Append( style.ToString() );
            builder.Append( ">" );
        }

        public HtmlTableBuilder TrBegin()
        {
            builder.Append( "<tr>" );
            return this;
        }

        public HtmlTableBuilder TrBegin( HtmlProperty proprety, HtmlStyle style )
        {
            builder.Append( "<tr" );
            if ( proprety != null )
                builder.Append( proprety.ToString() );
            if ( style != null )
                builder.Append( style.ToString() );
            builder.Append( ">" );
            return this;
        }

        public HtmlTableBuilder TrEnd()
        {
            builder.Append( "</tr>" );
            return this;
        }

        public HtmlTableBuilder TdBegin()
        {
            builder.Append( "<td>" );
            return this;
        }

        public HtmlTableBuilder TdBegin( object text )
        {
            builder.Append( "<td>" ).Append( ( text ?? "" ) );
            return this;
        }

        public HtmlTableBuilder TdBegin( HtmlProperty proprety, HtmlStyle style, object text )
        {
            builder.Append( "<td" );
            if ( proprety != null )
                builder.Append( proprety.ToString() );
            if ( style != null )
                builder.Append( style.ToString() );

            builder.Append( ">" );
            if ( text != null )
                builder.Append( text.ToString() );

            return this;
        }
        public HtmlTableBuilder TdBegin( HtmlProperty proprety )
        {
            return TdBegin( proprety, null, null );
        }
        public HtmlTableBuilder TdBegin( HtmlProperty proprety, HtmlStyle style )
        {
            return TdBegin( proprety, style, null );
        }

        public HtmlTableBuilder TdEnd()
        {
            builder.Append( "</td>" );
            return this;
        }

        public HtmlTableBuilder Append( object text )
        {
            builder.Append( text.ToString() );
            return this;
        }

        public string Html
        {
            get { return builder.Append( "</table>" ).ToString(); }
        }

        public override string ToString()
        {
            return Html;
        }
    }

    public sealed class HtmlProperty
    {
        private DictionaryEntry[] propertys = null;
        public HtmlProperty() { }
        public HtmlProperty( DictionaryEntry[] propertys )
        {
            this.propertys = propertys;
        }

        public override string ToString()
        {
            if ( propertys == null || propertys.Length == 0 )
                return "";

            StringBuilder builder = new StringBuilder();
            foreach ( DictionaryEntry entry in propertys )
            {
                builder.AppendFormat( " {0}=\"{1}\"", entry.Key, entry.Value );
            }

            return builder.ToString();
        }
    }

    public sealed class HtmlStyle
    {
        private DictionaryEntry[] propertys = null;
        public HtmlStyle() { }
        public HtmlStyle( DictionaryEntry[] propertys )
        {
            this.propertys = propertys;
        }

        public override string ToString()
        {
            if ( propertys == null || propertys.Length == 0 )
                return "";

            StringBuilder builder = new StringBuilder(" style=\" ");
            foreach ( DictionaryEntry entry in propertys )
            {
                builder.AppendFormat( "{0}:\"{1}; \"", entry.Key, entry.Value );
            }
            builder.Append("\"");

            return builder.ToString();
        }
    }
}
